From 82ae7b77cafad6c9370eb2d6ec56b14731147928 Mon Sep 17 00:00:00 2001 From: Tristan Van Berkom Date: Sat, 5 Mar 2011 19:29:10 +0900 Subject: [PATCH] Reduce memory consumption of the size request cache. This patch makes contextual height-for-width request caching optional (the contextual cache is not allocated for widgets that report GTK_SIZE_REQUEST_CONSTANT_SIZE). --- gtk/gtksizerequest.c | 168 ++++++++++++++++++++++++++++------------- gtk/gtkwidget.c | 3 + gtk/gtkwidgetprivate.h | 20 +++-- 3 files changed, 132 insertions(+), 59 deletions(-) diff --git a/gtk/gtksizerequest.c b/gtk/gtksizerequest.c index 81edba6a42..b27fd05f17 100644 --- a/gtk/gtksizerequest.c +++ b/gtk/gtksizerequest.c @@ -34,27 +34,114 @@ /* looks for a cached size request for this for_size. If not * found, returns the oldest entry so it can be overwritten * - * Note that this caching code was directly derived from + * Note that this caching code was originally derived from * the Clutter toolkit. */ + + +/* This function checks if 'request_needed' flag is present + * and resets the cache state if a request is needed for + * a given orientation. + */ +static SizeRequestCache * +init_cache (GtkWidget *widget, + GtkSizeGroupMode orientation) +{ + GtkSizeRequestMode mode; + SizeRequestCache *cache; + + cache = _gtk_widget_peek_request_cache (widget); + + if (orientation == GTK_SIZE_GROUP_HORIZONTAL && + _gtk_widget_get_width_request_needed (widget)) + { + mode = gtk_widget_get_request_mode (widget); + + if (mode == GTK_SIZE_REQUEST_CONSTANT_SIZE) + { + if (cache->sizes) + { + g_slice_free (ContextualSizes, cache->sizes); + cache->sizes = NULL; + } + } + else + { + if (!cache->sizes) + cache->sizes = g_slice_new0 (ContextualSizes); + + memset (cache->sizes->widths, 0x0, GTK_SIZE_REQUEST_CACHED_SIZES * sizeof (SizeRequest)); + cache->sizes->cached_widths = 0; + cache->sizes->last_cached_width = 0; + } + + cache->cached_width.minimum_size = -1; + cache->cached_width.natural_size = -1; + } + else if (orientation == GTK_SIZE_GROUP_VERTICAL && + _gtk_widget_get_height_request_needed (widget)) + { + mode = gtk_widget_get_request_mode (widget); + + if (mode == GTK_SIZE_REQUEST_CONSTANT_SIZE) + { + if (cache->sizes) + { + g_slice_free (ContextualSizes, cache->sizes); + cache->sizes = NULL; + } + } + else + { + if (!cache->sizes) + cache->sizes = g_slice_new0 (ContextualSizes); + + memset (cache->sizes->heights, 0x0, GTK_SIZE_REQUEST_CACHED_SIZES * sizeof (SizeRequest)); + cache->sizes->cached_heights = 0; + cache->sizes->last_cached_height = 0; + } + + cache->cached_height.minimum_size = -1; + cache->cached_height.natural_size = -1; + } + + return cache; +} + static gboolean -get_cached_size (SizeRequestCache *cache, +get_cached_size (GtkWidget *widget, GtkSizeGroupMode orientation, gint for_size, - SizeRequest **result) + CachedSize **result) { - guint i, n_sizes; - SizeRequest *cached_sizes; + SizeRequestCache *cache; + SizeRequest *cached_sizes; + guint i, n_sizes; + + cache = init_cache (widget, orientation); + + if (for_size < 0) + { + if (orientation == GTK_SIZE_GROUP_HORIZONTAL) + *result = &cache->cached_width; + else + *result = &cache->cached_height; + + if ((*result)->minimum_size < 0) + return FALSE; + else + return TRUE; + } if (orientation == GTK_SIZE_GROUP_HORIZONTAL) { - cached_sizes = cache->widths; - n_sizes = cache->cached_widths; + cached_sizes = cache->sizes->widths; + n_sizes = cache->sizes->cached_widths; } else { - cached_sizes = cache->heights; - n_sizes = cache->cached_widths; + cached_sizes = cache->sizes->heights; + n_sizes = cache->sizes->cached_widths; } /* Search for an already cached size */ @@ -62,7 +149,7 @@ get_cached_size (SizeRequestCache *cache, { if (cached_sizes[i].for_size == for_size) { - *result = &cached_sizes[i]; + *result = &cached_sizes[i].cached_size; return TRUE; } } @@ -72,33 +159,35 @@ get_cached_size (SizeRequestCache *cache, * and increment the last_cached_width/height right away */ if (orientation == GTK_SIZE_GROUP_HORIZONTAL) { - if (cache->cached_widths < GTK_SIZE_REQUEST_CACHED_SIZES) + if (cache->sizes->cached_widths < GTK_SIZE_REQUEST_CACHED_SIZES) { - cache->cached_widths++; - cache->last_cached_width = cache->cached_widths - 1; + cache->sizes->cached_widths++; + cache->sizes->last_cached_width = cache->sizes->cached_widths - 1; } else { - if (++cache->last_cached_width == GTK_SIZE_REQUEST_CACHED_SIZES) - cache->last_cached_width = 0; + if (++cache->sizes->last_cached_width == GTK_SIZE_REQUEST_CACHED_SIZES) + cache->sizes->last_cached_width = 0; } - *result = &cache->widths[cache->last_cached_width]; + cache->sizes->widths[cache->sizes->last_cached_width].for_size = for_size; + *result = &cache->sizes->widths[cache->sizes->last_cached_width].cached_size; } else /* GTK_SIZE_GROUP_VERTICAL */ { - if (cache->cached_heights < GTK_SIZE_REQUEST_CACHED_SIZES) + if (cache->sizes->cached_heights < GTK_SIZE_REQUEST_CACHED_SIZES) { - cache->cached_heights++; - cache->last_cached_height = cache->cached_heights - 1; + cache->sizes->cached_heights++; + cache->sizes->last_cached_height = cache->sizes->cached_heights - 1; } else { - if (++cache->last_cached_height == GTK_SIZE_REQUEST_CACHED_SIZES) - cache->last_cached_height = 0; + if (++cache->sizes->last_cached_height == GTK_SIZE_REQUEST_CACHED_SIZES) + cache->sizes->last_cached_height = 0; } - *result = &cache->heights[cache->last_cached_height]; + cache->sizes->heights[cache->sizes->last_cached_height].for_size = for_size; + *result = &cache->sizes->heights[cache->sizes->last_cached_height].cached_size; } return FALSE; @@ -168,39 +257,11 @@ compute_size_for_orientation (GtkWidget *widget, gint *minimum_size, gint *natural_size) { - SizeRequestCache *cache; - SizeRequest *cached_size; + CachedSize *cached_size; gboolean found_in_cache = FALSE; - int adjusted_min, adjusted_natural; - - cache = _gtk_widget_peek_request_cache (widget); + gint adjusted_min, adjusted_natural; - if (orientation == GTK_SIZE_GROUP_HORIZONTAL) - { - cached_size = &cache->widths[0]; - - if (!_gtk_widget_get_width_request_needed (widget)) - found_in_cache = get_cached_size (cache, orientation, for_size, &cached_size); - else - { - memset (cache->widths, 0, GTK_SIZE_REQUEST_CACHED_SIZES * sizeof (SizeRequest)); - cache->cached_widths = 1; - cache->last_cached_width = 0; - } - } - else - { - cached_size = &cache->heights[0]; - - if (!_gtk_widget_get_height_request_needed (widget)) - found_in_cache = get_cached_size (cache, orientation, for_size, &cached_size); - else - { - memset (cache->heights, 0, GTK_SIZE_REQUEST_CACHED_SIZES * sizeof (SizeRequest)); - cache->cached_heights = 1; - cache->last_cached_height = 0; - } - } + found_in_cache = get_cached_size (widget, orientation, for_size, &cached_size); if (!found_in_cache) { @@ -282,7 +343,6 @@ compute_size_for_orientation (GtkWidget *widget, cached_size->minimum_size = min_size; cached_size->natural_size = nat_size; - cached_size->for_size = for_size; if (orientation == GTK_SIZE_GROUP_HORIZONTAL) _gtk_widget_set_width_request_needed (widget, FALSE); diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 5c28ef190d..00f9be591f 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -10669,6 +10669,9 @@ gtk_widget_finalize (GObject *object) if (priv->context) g_object_unref (priv->context); + if (priv->requests.sizes) + g_slice_free (ContextualSizes, priv->requests.sizes); + if (g_object_is_floating (object)) g_warning ("A floating object was finalized. This means that someone\n" "called g_object_unref() on an object that had only a floating\n" diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index 1e91290d05..9dfec658e2 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -34,15 +34,18 @@ G_BEGIN_DECLS * (Note this define is limited by the bitfield sizes * defined on the SizeRequestCache structure). */ -#define GTK_SIZE_REQUEST_CACHED_SIZES (3) +#define GTK_SIZE_REQUEST_CACHED_SIZES (2) + +typedef struct { + gint minimum_size; + gint natural_size; +} CachedSize; typedef struct { /* the size this request is for */ - gint for_size; - - gint minimum_size; - gint natural_size; + gint for_size; + CachedSize cached_size; } SizeRequest; typedef struct { @@ -53,6 +56,13 @@ typedef struct { guint cached_heights : 2; guint last_cached_width : 2; guint last_cached_height : 2; +} ContextualSizes; + +typedef struct { + ContextualSizes *sizes; + + CachedSize cached_width; + CachedSize cached_height; } SizeRequestCache; void _gtk_widget_set_visible_flag (GtkWidget *widget, -- 2.30.2